#include <iostream>
#include "httplib.h"
#include "ContactException.hpp"
#include "add_contact.pb.h"

using std::cerr;
using std::cin;
using std::cout;
using std::endl;

using namespace httplib;

#define CONTACT_HOST "82.157.3.118"
#define CONTACT_PORT 8888

void menu()
{
    std::cout << "-----------------------------------------------------" << std::endl
              << "--------------- 请选择对通讯录的操作 ----------------" << std::endl
              << "------------------ 1、新增联系⼈ --------------------" << std::endl
              << "------------------ 2、删除联系⼈ --------------------" << std::endl
              << "------------------ 3、查看联系⼈列表 ----------------" << std::endl
              << "------------------ 4、查看联系⼈详细信息 ------------" << std::endl
              << "------------------ 0、退出 --------------------------" << std::endl
              << "-----------------------------------------------------" << std::endl;
}

void BuildAddContactRequest(Add_http_contacts::AddContactRequest *req)
{
    std::cout << "--------------新增联系人--------------" << std::endl;
    std::cout << "请输入联系人的姓名: ";
    std::string name;
    getline(std::cin, name);
    req->set_name(name);

    std::cout << "请输入联系人的年龄: ";
    int age;
    std::cin >> age;
    req->set_age(age);
    std::cin.ignore(256, '\n'); // 清除缓冲区所有内容，直到'\n'，把'\n'删除后结束，或者清除256个字节直接结束

    for (int i = 0;; i++)
    {
        std::cout << "请输入联系人的电话: " << i + 1 << "(只输入回车完成电话新增): ";
        std::string number;
        getline(std::cin, number);
        if (number.empty())
            break;
        // 接收add_phone返回的phone对象
        Add_http_contacts::AddContactRequest_Phone *phone = req->add_phone();
        phone->set_num(number);

        std::cout << "请输入联系人的电话类型:(0.移动电话, 1.固定电话): ";
        int type;
        std::cin >> type;
        std::cin.ignore(256, '\n');
        switch (type)
        {
        case 0:
            phone->set_type(Add_http_contacts::AddContactRequest_Phone_PhoneType::AddContactRequest_Phone_PhoneType_MP);
            break;
        case 1:
            phone->set_type(Add_http_contacts::AddContactRequest_Phone_PhoneType::AddContactRequest_Phone_PhoneType_TEL);
            break;
        default:
            std::cout << "输入有误, 请重新根据提示输入" << std::endl;
            break;
        }
    }
}
void AddContact()
{
    Client client(CONTACT_HOST, CONTACT_PORT);
    // 构建req对象
    Add_http_contacts::AddContactRequest req;
    BuildAddContactRequest(&req);
    // 序列化
    std::string req_str;
    if (!req.SerializeToString(&req_str))
    {
        std::string errstr = "AddContact时,序列化失败";
        throw ContactException(errstr);
    }
    // 发起post请求
    auto post = client.Post("/contacts/add", req_str, "application/protobuf");
    if (!post) 
    {
        std::string err_str = "/contacts/add 链接失败,错误原因: ";
        err_str.append(httplib::to_string(post.error()));
        throw ContactException(err_str);
    }

    // 反序列化rsp
    Add_http_contacts::AddContactResponse resp;
    bool parse = resp.ParseFromString(post->body);
    if (post->status != 200 && !parse)
    {
        std::string err_str = "调用 /contact/add 失败 ";
        err_str.append(std::to_string(post->status))
            .append("(")
            .append(post->reason)
            .append(")");
        throw ContactException(err_str);
    }
    else if (post->status != 200)
    {
        std::string err_str = "调用 /contact/add 失败 ";
        err_str.append(std::to_string(post->status))
            .append("(")
            .append(post->reason)
            .append(")")
            .append("错误原因: ")
            .append(resp.error_desc());
        throw ContactException(err_str);
    }
    else if (!resp.success())
    {
        std::string err_str = "调用 /contact/add 结果异常 ";
        err_str.append("异常原因: ")
            .append(resp.error_desc());
        throw ContactException(err_str);
    }
    // 打印结果
    cout << "新增联系人成功" << "联系人id: " << resp.uuid() << endl;
}

int main()
{
    enum Option
    {
        Quit = 0,
        Add,
        Del,
        Findone,
        Findall
    };
    menu();
    cout << "---->请选择: ";
    int choose;
    cin >> choose;
    cin.ignore(256, '\n');
    try
    {
        switch (choose)
        {
        case Option::Quit:
            cout << "---->退出" << endl;
            return 1;
        case Option::Add:
            cout << "---->新增联系人" << endl;
            AddContact();
            break;
        case Option::Del:
            cout << "---->暂未实现" << endl;
            break;
        case Option::Findone:
            cout << "---->暂未实现" << endl;
            break;
        case Option::Findall:
            cout << "---->暂未实现" << endl;
            break;
        default:
            cout << "---->选择有误，请重新选择" << endl;
            break;
        };
    }
    catch (const ContactException &e)
    {
        cout << "--->出现错误, 错误原因是: " << e.What() << endl;
    }
}
